/**
    是实现高级的打印功能
*/
#include "stdarg.h"
#include "common.h"
#include "spinlock.h"

// 定义自旋锁
static struct {
    struct spinlock lock;
    int locking;          // 开启自旋锁
} pr;

static char digits[] = "0123456789abcdef";  // 最多支持16进制的数字字符映射表 
// 以指定进制打印整数
// num: 要打印的整数; base: 进制; sign: 是否处理符号
static void printint(long long num, int base, int sign) {
    char buf[16];  // 用于存储转换后的数字字符
    uint64 n;

    // 检查是否需要处理符号
    if(sign && (sign = (num < 0))) {
        n = -num;           // 需要处理符号且输入为负数时，使用其绝对值
    } else {
        n = num;            // 不需要处理符号或输入为正数时，直接使用输入值
    }
    // 转换进制并逆序存储
    int i = 0;
    do {
        buf[i++] = digits[n % base];  // 取余得到末尾数字字符
    } while((n /= base) != 0);
    // 输出符号
    if(sign) {
        buf[i++] = '-';
    }
    // 逆序输出数字字符
    while(--i >= 0) {
        consputc(buf[i]);
    }
}

// 打印指针地址（十六进制）
static void printptr(uint64 ptr) {
    // 输出前缀
    consputc('0');
    consputc('x');
    // 输出的位数为字节数的两倍，因为1个十六进制位表示4个二进制位，而8个二进制位为1个字节
    // 每次左移4位，每次取最高4位，即不重复的从左到右4位一组读取
    for(int i = 0; i < (sizeof(ptr) << 1); i++, ptr <<= 4) {
        consputc(digits[ptr >> (sizeof(ptr) * 8 - 4)]);
    }
}

// 格式化打印到控制台
int printf(char *fmt, ...) {
    va_list ap;
    char *s;
    int locking;
    locking = pr.locking;
    if(locking) {
        // 则获取自旋锁
        acquire(&pr.lock);
    }
    // 初始化可变参数列表
    va_start(ap, fmt);

    for(int i = 0; fmt[i]; i++) {
        if(fmt[i] != '%') {
            // 非格式化字符，直接输出
            consputc(fmt[i]);
            continue;
        }
        // 处理格式化字符，跳过'%'
        i++;
        switch(fmt[i]) {
            case 'd':  // 十进制整数
                printint(va_arg(ap, int), 10, 1);
                break;
            case 'x':  // 十六进制整数
                printint(va_arg(ap, int), 16, 0);
                break;
            case 'p':  // 指针地址
                printptr(va_arg(ap, unsigned long));
                break;
            case 's':  //字符串
                if((s = va_arg(ap, char*)) == 0) {
                    // 如果字符串指针为空，则输出"(null)"
                    s = "(null)";
                }
                for(; *s; s++) {
                    consputc(*s);
                }
                break;
            case 'c':  // 字符
                consputc(va_arg(ap, int));
                break;
            case '%':  // 百分号
                consputc('%');
                break;
            default:  // 未知格式
                consputc('%');
                consputc(fmt[i]);
                break;
        }
    }
    // 清理可变参数列表
    va_end(ap);

    if(locking) {
        // 释放自旋锁
        release(&pr.lock);
    }
    return 0;
}

void panic(char *s) {
    pr.locking = 0;        // 发生致命错误，关闭自旋锁，确保可以继续输出报错信息
    printf("严重错误: %s\n", s);
    while(1){
        // 进入死循环
    }
}

// 初始化printf打印函数
void printfinit(void) {
    initlock(&pr.lock, "pr");
    pr.locking = 1;
}